package dao;

import cn.demoncat.util.es.dao.BaseEsDao;
import cn.demoncat.util.es.util.AggregationUtil;
import cn.demoncat.util.es.util.EsUtil;
import cn.demoncat.util.es.util.QueryBuilderUtil;
import cn.demoncat.util.es.util.QueryUtil;
import cn.demoncat.util.lang.entity.ListStr;
import cn.demoncat.util.lang.entity.MapSo;
import cn.demoncat.util.lang.entity.NameValues;
import cn.demoncat.util.lang.entity.Pager;
import cn.demoncat.util.lang.entity.report.SidCount;
import doc.MallItemDoc;
import entity.MallItemParam;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.search.aggregations.bucket.MultiBucketsAggregation;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.core.query.HighlightQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 商品
 *
 * @author 延晓磊
 * @since 2023年03月13日
 */
@Component
public class MallItemDao extends BaseEsDao<MallItemDoc,String> {

    /**
     * 建议列表
     *
     * @param kw    关键词：商品名称
     * @return
     *
     * @author 延晓磊
     * @since 2021年01月19日
     */
    public List<String> suggest(String kw){
        return this.completionSuggest(kw, "title");
    }

    /**
     * 建议列表 + 统计
     *
     * @param kw    关键词：商品名称
     * @return
     *
     * @author 延晓磊
     * @since 2021年01月19日
     */
    public List<SidCount> suggestCount(String kw){
        // 查询建议
        List<String> list = this.completionSuggest(kw, "title");
        if (list.isEmpty()) {
            return new ArrayList<>();
        }else{
            return list.parallelStream().map(o -> new SidCount(o, count(QueryUtil.match("name", o)))).collect(Collectors.toList());
        }
    }

    /**
     * 搜索
     *
     * @param param
     * @return
     *
     * @author 延晓磊
     * @since 2023年04月03日
     */
    public Pager<MallItemDoc> search(MallItemParam param){
        // 排序方式
        Sort sort = null;
        if (StringUtils.isNotBlank(param.getSort())) {
            switch (param.getSort()) {
                case "10":
                    sort = QueryUtil.getSort("price");
                    break;
                case "11":
                    sort = QueryUtil.getSort("price", false);
                    break;
                case "20":
                    sort = QueryUtil.getSort("sellNum");
                    break;
                case "21":
                    sort = QueryUtil.getSort("sellNum", false);
                    break;
                default:
                    break;
            }
        }

        // 搜索条件 - 计分
        BoolQueryBuilder query = QueryBuilderUtil.bool();
        HighlightQuery high = null;
        if (StringUtils.isNotBlank(param.getName())) {
            // 名称
            query.must(QueryBuilderUtil.match("name", param.getName()));
            // 高亮
            high = QueryUtil.getHigh("name");
        }

        // 过滤条件 - 不计分
        NativeSearchQuery searchQuery = new NativeSearchQuery(query);
        // - 限定条件
        // - 卖方
        if (StringUtils.isNotBlank(param.getSeller())) {
            query.filter(QueryBuilderUtil.term("seller", param.getSeller()));
        }
        // - 库存
        if (StringUtils.isNotBlank(param.getStockStatus())) {
            query.filter(QueryBuilderUtil.term("stockStatus", param.getStockStatus()));
        }
        // - 价格
        if (param.getPrice() != null) {
            query.filter(QueryBuilderUtil.between("price", param.getPrice().getMax(), param.getPrice().getMin()));
        }
        // - 分类
        if (StringUtils.isBlank(param.getCatId())) {
            searchQuery.addAggregation(AggregationUtil.terms("catId").size(10000));
        }else{
            if (param.getCatId().length() == 9) {
                // 叶子分类：精确查询
                query.filter(QueryBuilderUtil.term("catId", param.getCatId()));
            }else{
                // 分支分类：前缀查询
                query.filter(QueryBuilderUtil.prefix("catId", param.getCatId()));
                searchQuery.addAggregation(AggregationUtil.terms("catId"));
            }
        }
        // - 规格
        searchQuery.addAggregation(AggregationUtil.nested("param", AggregationUtil.terms("name", "param.name").subAggregation(AggregationUtil.terms("value", "param.value").size(100))));
        if (MapUtils.isNotEmpty(param.getParams())) {
            for (Map.Entry<String,ListStr> entry : param.getParams().entrySet()) {
                query.filter(QueryBuilderUtil.nested("param", QueryBuilderUtil.and(QueryBuilderUtil.term("param.name", entry.getKey()), QueryBuilderUtil.terms("param.value", entry.getValue()))));
            }
        }

        // 分页查询
        Pager<MallItemDoc> page = this.findPage(QueryUtil.addHigh(searchQuery, high), param.getPageNum(), param.getPageSize(), sort);

        // 高亮处理
        if (high != null) {
            List<List<String>> highs = EsUtil.getHigh(page, "name");
            List<String> title;
            for (int i = 0; i < page.getList().size(); i++) {
                title = highs.get(i);
                if (CollectionUtils.isNotEmpty(title)) {
                    page.getList().get(i).setTitle(title.get(0));
                }
            }
        }

        // 分组聚合
        MapSo map = MapSo.getInstance();
        List<? extends Terms.Bucket> buckets;
        // - 分类
        if (StringUtils.isBlank(param.getCatId()) || param.getCatId().length() < 9) {
            buckets = EsUtil.getAgg(page, "catId");
            if (buckets.size() > 1) {
                map.put("catList", buckets.stream().map(MultiBucketsAggregation.Bucket::getKeyAsString).collect(Collectors.toList()));
            }
        }
        // - 规格
        buckets = EsUtil.getNestedAgg(page, "param", "name");
        if (buckets.size() > 1) {
            // 未筛选 && 选项大于1的规格
            map.put("paramList", buckets.stream().filter(o -> param.getParams() == null || !param.getParams().containsKey(o.getKeyAsString())).map(o -> new NameValues(o.getKeyAsString(), AggregationUtil.getTerms(o.getAggregations(), "value").stream().map(MultiBucketsAggregation.Bucket::getKeyAsString).collect(Collectors.toList()))).filter(o -> o.getValues().size() > 1).collect(Collectors.toList()));
        }
        page.setExt(map);
        return page;
    }


}
